#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "../ringbuffer.h"

struct ringbuffer
{
    int r_index;
    int w_index;

    uint8_t* element_array;
    int element_array_size;
    int element_size;
};


struct ringbuffer* ringbuffer_create(int element_size, uint8_t* element_array, int element_array_size)
{
    struct ringbuffer* p = (struct ringbuffer*)calloc(1, sizeof(struct ringbuffer));

    if (0 == p)
    {
        fprintf(stderr, "ringbuffer_create(): calloc\n");
        return 0;
    }

    if (0 != element_array_size % 8)
    {
        fprintf(stderr, "ringbuffer_create(): element_size mod 8 must be 0\n");
        free(p);
        return 0;
    }

    p->element_array = element_array;
    p->element_array_size = element_array_size;
    p->element_size = element_size;

    return p;
}

void ringbuffer_destroy(struct ringbuffer* p)
{
    free(p);
}

int ringbuffer_size(struct ringbuffer* p)
{
    return p->element_array_size;
}

int ringbuffer_count(struct ringbuffer* p)
{
    return (p->element_array_size - 1) & (p->w_index - p->r_index);
}

int ringbuffer_empty(struct ringbuffer* p)
{
    return 0 == ringbuffer_count(p);
}

int ringbuffer_full(struct ringbuffer* p)
{
    return (p->element_array_size - 1) == ringbuffer_count(p);
}

void* ringbuffer_read(struct ringbuffer* p)
{
    return (void*)(p->element_array + (p->r_index++ & (p->element_array_size - 1)));
}

void ringbuffer_write(struct ringbuffer* p, void* element, void (*cpf)(void* dest, void* src))
{
    void* e_dest = p->element_array + (p->w_index++ & (p->element_array_size - 1));

    if (0 == cpf)
    {
        memcpy(e_dest, element, p->element_size);
    }
    else
    {
        cpf(e_dest, element);
    }
}




